#ifndef __M_SINK_H__
#define __M_SINK_H__

#include "util.hpp"
#include <memory>
#include <cassert>
class LogSink
{
public:
    using ptr = shared_ptr<LogSink>;
    LogSink() {}
    virtual ~LogSink() {}
    virtual void log(const char *data, size_t len) = 0;
};

class StdoutSink : public LogSink
{
public:
    using ptr = shared_ptr<StdoutSink>;
    virtual void log(const char *data, size_t len)
    {
        cout.write(data, len);
    }
};

class FileSink : public LogSink
{
private:
    string _filename;
    ofstream _ofs;

public:
    using ptr = shared_ptr<FileSink>;
    FileSink(const string &filename) : _filename(filename)
    {
        log_util::file::create_directory(log_util::file::path(_filename));
        _ofs.open(_filename, ios::binary | ios::app);
        assert(_ofs.is_open());
    }
    void log(const char *data, size_t len)
    {
        _ofs.write(data, len);
        if (_ofs.good() == false)
        {
            cout << "日志文件输出失败!" << endl;
        }
    }
};

class RollBySizeSink : public LogSink
{
private:
    string _basename;
    ofstream _ofs;
    size_t _max_fsize;
    size_t _cur_fsize;
    size_t count = 0;
    string createNewFile()
    {
        time_t t = log_util::date::now();
        struct tm lt;
        localtime_r(&t, &lt);
        stringstream filename;
        filename << _basename;
        filename << lt.tm_year;
        filename << lt.tm_mon;
        filename << lt.tm_mday;
        filename << lt.tm_hour;
        filename << lt.tm_min;
        filename << lt.tm_sec;
        filename << "-";
        filename << count++;
        filename << ".log";
        return filename.str();
    }

public:
    RollBySizeSink(const string &basename, size_t max_size) : _basename(basename), _max_fsize(max_size), _cur_fsize(0)
    {
        string pathname = createNewFile();
        log_util::file::create_directory(log_util::file::path(pathname));
        _ofs.open(pathname, std::ios::binary | ios::app);
        assert(_ofs.is_open());
    }

    void log(const char *data, size_t len)
    {
        if (_cur_fsize >= _max_fsize)
        {
            _ofs.close();
            string pathname = createNewFile();
            _ofs.open(pathname, std::ios::binary | ios::app);
            assert(_ofs.is_open());
            _cur_fsize = 0;
        }
        _ofs.write(data, len);
        assert(_ofs.good());
        _cur_fsize += len;
    }
};

class SinkFactory
{
public:
    template <typename SinkType, typename... Args>
    static LogSink::ptr create(Args &&...args)
    {
        return make_shared<SinkType>(forward<Args>(args)...);
    }
};
#endif